/*Copyright (C) 2009 - 2011 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include "bool.h"
#include "containers.h"

/*
 Schéma de la liste:
       +<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-+
       |                                                          |
 List -+-> structList -+->data                                    |
                       +->next -> NULL  (premier de la liste)   |
                       +->prev -> structList -+->data             |
                                              +->next ->->->->->--+
                                              +->prev -> NULL (dernier)
*/

/*
** Permet d'insérer un élément en fin de liste.
*/

void Container_PushBack(Container *list, void *ptr) {
	structContainer *newNode = malloc(sizeof(structContainer));
	newNode->prev = EMPTY_CONTAINER;
	newNode->ptr = ptr;

	if(*list != EMPTY_CONTAINER) {
		structContainer *temp = *list;

		while(temp->prev != EMPTY_CONTAINER) {
			temp = temp->prev;
		}

		temp->prev = newNode;

		newNode->next = temp;
	}
	else {
		*list = newNode;
	}
}

/*
** Permet d'insérer un élément en début de liste.
*/
void Container_PushUp(Container *list, void *ptr) {
	structContainer *newNode = malloc(sizeof(structContainer));
	newNode->next = EMPTY_CONTAINER;
	newNode->prev = *list;
	newNode->ptr = ptr;

	if(*list != EMPTY_CONTAINER) {
		(*list)->next = newNode;
	}

	*list = newNode;
}

/*
** Permet d'insérer un élément dans la liste.
*/
void Container_Insert(Container *list, void *ptr, int index) {
	if(index == 0) {
		Container_PushUp(list, ptr);
	}
	else {
		int i = 0;
		structContainer *tempPrev, *tempNext;
		structContainer *newNode = malloc(sizeof(structContainer));
		newNode->ptr = ptr;
		tempNext = *list;

		while(i < index - 1) {
			tempNext = tempNext->prev;
			i++;
		}

		tempPrev = tempNext->prev;

		tempPrev->next = newNode;
		tempNext->prev = newNode;
		newNode->next = tempNext;
		newNode->prev = tempPrev;
	}
}

/*
** Permet de supprimer l'élément en fin de liste.
*/
void Container_PopBack(Container *list) {
	structContainer *tempToDel, *tempNewEnd;
	tempToDel = *list;

	if(tempToDel->prev == EMPTY_CONTAINER) {
		Container_PopUp(list);
	}
	else {
		while(tempToDel->prev != EMPTY_CONTAINER) {
			tempToDel = tempToDel->prev;
		}

		tempNewEnd = tempToDel->next;

		tempNewEnd->prev = EMPTY_CONTAINER;
		free(tempToDel);
	}
}

/*
** Permet de supprimer l'élément en tête de liste.
*/
void Container_PopUp(Container *list) {
	structContainer *temp = *list;

	if(temp->prev == EMPTY_CONTAINER) {
		free(temp);
		*list = EMPTY_CONTAINER;
	}
	else {
		temp = temp->prev;
		free(temp->next);
		temp->next = EMPTY_CONTAINER;
		*list = temp;
	}
}

/*
** Permet de supprimer un élément.
*/
void Container_Delete(Container *list, int index) {
	if(index == 0) {
		Container_PopUp(list);
	}
	else {
		int i = 0;
		structContainer *tempPrev, *tempNext;
		tempNext = *list;

		while(i < index - 1) {
			tempNext = tempNext->prev;
			i++;
		}

		tempPrev = tempNext->prev->prev;

		free(tempNext->prev);
		tempNext->prev = tempPrev;

		if(tempPrev != EMPTY_CONTAINER) {
			tempPrev->next = tempNext;
		}
	}
}

/*
** Permet de connaitre la taille de la liste.
*/
int Container_Size(Container list) {
	structContainer *temp = list;
	int i = 0;

	if(temp != EMPTY_CONTAINER) {
		i++;

		while(temp->prev != EMPTY_CONTAINER) {
			temp = temp->prev;
			i++;
		}
	}

	return i;
}

/*
** Permet de vider la liste de ses éléments.
*/
void Container_Clear(Container *list) {
	structContainer *temp = *list;

	if(temp != EMPTY_CONTAINER) {
		while(temp->prev != EMPTY_CONTAINER) {
			temp = temp->prev;
			free(temp->next);
		}

		free(temp);

		*list = EMPTY_CONTAINER;
	}
}

/*
** Permet de récupérer un élément.
*/
void *Container_Get(Container list, int index) {
	int i = 0;
	structContainer *temp = list;

	while(i < index) {
		temp = temp->prev;
		i++;
	}

	return temp->ptr;
}

/*
** Permet d'initialiser un élément de la liste
*/
void Container_Set(Container *list, void *ptr, int index) {
	int i = 0;
	structContainer *temp = *list;

	while(i < index) {
		temp = temp->prev;
		i++;
	}

	temp->ptr = ptr;
}

